﻿using System;
using System.Reflection;
using Autofac;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc.Cors.Internal;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using ZilLion.Service.Core.Infrastructure.Filters;
using ZilLion.Service.Core.Infrastructure.Middleware;
using ZilLion.Service.Core.Ioc;
using ZilLion.Service.Core.Log;
using ZilLion.Service.Core.Snowflake;
using ZilLion.Service.Core.Starter.Config;

namespace ZilLion.Service.Core.App
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
            SnowflakeIdCreater.Instance().Init(); //初始化全局雪花ID
        }

        public IConfiguration Configuration { get; }

        public void ConfigureContainer(ContainerBuilder builder)
        {
            IocConfig.Configure(builder, Assembly.GetExecutingAssembly());
        }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            CorsConfig.ConfigureServices(services);
            services.AddMvc(option =>
            {
                option.Filters.Add(new JwtTokenFilter());
                option.Filters.Add(new CorsAuthorizationFilterFactory(CorsConfig.DefaultCorsPolicyName));
            }).AddControllersAsServices().AddJsonOptions(options =>
            {
                //使用驼峰样式的key
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                //设置时间格式
                options.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                options.SerializerSettings.Error = (sender, args) =>
                {
                    var guid = Guid.NewGuid().ToString("N");

                    var msg =
                        $"在处理类型{args.ErrorContext.OriginalObject.GetType().Name}时发生错误,path为:{args.ErrorContext.Path},Member为:{args.ErrorContext.Member.ToString()}";
                    ZilLionLogManager.Instance().Warn(msg, tags: guid);
                    ZilLionLogManager.Instance().Error(args.ErrorContext.Error, tags: guid);
                };
            });

            SwaggerGenConfig.ConfigureServices(services);
            services.AddResponseCaching();
            services.TryAddScoped<JwtInfoContainer>();
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
                app.UseDeveloperExceptionPage();
            else
                app.UseErrorHandling();
            app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()); // Enable CORS! TODO 此处应该可以取配置,以保证安全
           
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                                   ForwardedHeaders.XForwardedProto
            });
            app.UseResponseCaching();
            app.UseSwagger();
            // Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)

            app.UseSwaggerUI(options =>
            {
                options.InjectOnCompleteJavaScript("/swagger_lang.js");
                options.SwaggerEndpoint("/swagger/v1/swagger.json", "MvcApp API V1");
                options.ShowJsonEditor();
            }); // URL: /swagger

            RouteConfig.Configure(app);
        }
    }
}